/*
 * Copyright (c) 2024-2025 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#ifndef MX_LIST_H
#define MX_LIST_H

#include <tools/macros.h>

#define LIST_POISON1 ((void *)0x0)
#define LIST_POISON2 ((void *)0x0)

#define LIST_INIT(li) { .prev = &li, .next = &li }

#define list_foreach(pos, head, type, member)                                        \
    for ((pos) = container_of((head)->next, type, member); &(pos)->member != (head); \
         (pos) = container_of((pos)->member.next, type, member))

#define list_foreach_safe(pos, n, head, type, member)                                                      \
    for (pos = container_of((head)->next, type, member), n = container_of(pos->member.next, type, member); \
         &pos->member != (head); pos = n, n = container_of(n->member.next, type, member))

#ifndef assert
#define assert(x)
#endif

typedef struct l__list {
    struct l__list *prev;
    struct l__list *next;
} list_t;

typedef void *slist_t;

static inline void list_init(list_t *li)
{
    assert(li != 0);

    li->prev = li;
    li->next = li;
}

static inline void list_insert(list_t *front, list_t *node)
{
    assert(front != 0);
    assert(node != 0);

    node->next       = front->next;
    node->prev       = front;
    front->next      = node;
    node->next->prev = node;
}

static inline void list_append(list_t *head, list_t *node)
{
    assert(head != 0);
    assert(node != 0);

    head->prev->next = node;
    node->prev       = head->prev;
    head->prev       = node;
    node->next       = head;
}

static inline void list_remove(list_t *node)
{
    assert(node != 0);

    node->next->prev = node->prev;
    node->prev->next = node->next;

    list_init(node);
}

static inline void list_del(list_t *node)
{
    node->next->prev = node->prev;
    node->prev->next = node->next;

    node->next = (list_t *)LIST_POISON1;
    node->prev = (list_t *)LIST_POISON2;
}

static inline _Bool list_is_empty(list_t *head)
{
    return head->next == head;
}

static inline int list_count(list_t *head)
{
    int     count  = 0;
    list_t *p_head = head;

    while (p_head->next != head) {
        count++;
        p_head = p_head->next;
    }
    return count;
}

static inline int list_tryremove(list_t *head, list_t *node)
{
    assert(node != head);
    assert(head != 0);
    assert(node != 0);

    list_t *ctas = head->next;

    while ((ctas != head) && (ctas != node)) {
        ctas = ctas->next;
    }
    if (ctas == head)
        return 0;

    node->next->prev = node->prev;
    node->prev->next = node->next;

    list_init(node);
    return 1;
}

static inline void local_list_add(list_t *_new, list_t *prev, list_t *next)
{
    next->prev = _new;
    _new->next = next;
    _new->prev = prev;
    prev->next = _new;
}

#define slist_push(top, obj)  \
    do {                      \
        slist_t tmp = top;    \
        top         = &(obj); \
        obj         = tmp;    \
    } while (0);

#define slist_append(tail, obj)      \
    do {                             \
        *(slist_t *)(tail) = &(obj); \
        (tail)             = &(obj); \
        (obj)              = NULL;   \
    } while (0);

#define slist_foreach(pos, head, type, member)                  \
    for (pos = container_of((head), type, member); pos && head; \
         pos = pos->member ? container_of(pos->member, type, member) : 0)

static inline slist_t slist_pop(slist_t *top)
{
    slist_t rtn = (*top);
    (*top)      = *((slist_t *)(*top));
    return rtn;
}

#define slist_remove(pos, head, type, member)                                           \
    do {                                                                                \
        type *atsp;                                                                     \
        if (head == &pos->member)                                                       \
            head = pos->member;                                                         \
        else {                                                                          \
            slist_foreach(atsp, (head), type, member) if (atsp->member == &pos->member) \
            {                                                                           \
                atsp->member = pos->member;                                             \
                break;                                                                  \
            }                                                                           \
        }                                                                               \
    } while (0)

static inline int slist_count(slist_t *top)
{
    slist_t *p   = top;
    int      rtn = 0;

    while (*p != NULL) {
        p = *p;
        rtn++;
    }
    return rtn;
}

#define list_first_entry(ptr, type, member) container_of((ptr)->next, type, member)

#endif
